﻿namespace HZY.Repository.FreeSql.Admin.Repositories.Impl;

public class RepositoryBaseImpl<T> : BaseRepository<T>, IRepository<T> where T : class
{
    /// <summary>
    /// 主键的 PropertyInfo 对象
    /// </summary>
    protected readonly PropertyInfo _keyPropertyInfo;

    public RepositoryBaseImpl(IFreeSql fsql, Expression<Func<T, bool>> filter, Func<string, string> asTable = null) : base(fsql, filter, asTable)
    {
        _keyPropertyInfo = typeof(T).GetKeyProperty(false);
    }

    /// <summary>
    /// 生成表达式树 例如：( w=>w.Key==Guid.Empty )
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public virtual Expression<Func<T, bool>> GetKeyExpression(object value)
        => ExpressionTreeExtensions.Equal<T, object>(_keyPropertyInfo.Name, value);

    #region 查询 单条数据

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public virtual T FindById<TKey>(TKey key)
    {
        if (key == null) throw new ArgumentNullException(nameof(key));

        return this.Select.Where(GetKeyExpression(key)).First();
    }

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public virtual Task<T> FindByIdAsync<TKey>(TKey key)
    {
        if (key == null) throw new ArgumentNullException(nameof(key));

        return this.Select.Where(GetKeyExpression(key)).FirstAsync();
    }

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual T Find(Expression<Func<T, bool>> expWhere)
        => this.Where(expWhere).First();

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<T> FindAsync(Expression<Func<T, bool>> expWhere)
        => this.Where(expWhere).FirstAsync();

    #endregion

    #region 查询 多条数据

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual List<T> ToListAll()
        => this.Select.ToList();

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual Task<List<T>> ToListAllAsync()
        => this.Select.ToListAsync();

    /// <summary>
    /// 获取列表 根据查询条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<List<T>> ToListAsync(Expression<Func<T, bool>> expWhere)
        => this.Select.Where(expWhere).ToListAsync();

    #endregion

    #region 更新

    /// <summary>
    /// 根据实体id更新数据
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual async Task<int> UpdateByIdAsync(T model)
    {
        if (_keyPropertyInfo == null) throw new Exception("模型未设置主键特性标记!");

        if (model == null) return 0;

        var keyValue = _keyPropertyInfo.GetValue(model);

        return await base.Select.Where(GetKeyExpression(keyValue))
             .ToUpdate()
             .SetSource(model)
             .ExecuteAffrowsAsync()
             ;
    }

    #endregion

    #region 删除

    /// <summary>
    /// 删除 根据id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual int DeleteById<TKey>(TKey key)
    {
        if (key == null) return 0;

        return Delete(GetKeyExpression(key));
    }

    /// <summary>
    /// 删除 根据 id集合
    /// </summary>
    /// <param name="keys"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual int DeleteByIds<TKey>(IEnumerable<TKey> keys)
    {
        if (_keyPropertyInfo == null) throw new Exception("模型未设置主键特性标记!");

        if (keys == null || keys.Count() == 0) return 0;

        var exp = ExpressionTreeExtensions.Contains<T, TKey>(_keyPropertyInfo.Name, keys);
        return Delete(exp);
    }

    /// <summary>
    /// 删除 根据 id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual async Task<int> DeleteByIdAsync<TKey>(TKey key)
    {
        if (key == null) return 0;

        return await DeleteAsync(GetKeyExpression(key));
    }

    /// <summary>
    /// 删除 根据id集合
    /// </summary>
    /// <param name="keys"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual async Task<int> DeleteByIdsAsync<TKey>(IEnumerable<TKey> keys)
    {
        if (_keyPropertyInfo == null) throw new Exception("模型未设置主键特性标记!");

        if (keys == null || keys.Count() == 0) return 0;

        var exp = ExpressionTreeExtensions.Contains<T, TKey>(_keyPropertyInfo.Name, keys);
        return await DeleteAsync(exp);
    }

    #endregion

    #region 是否存在 、 数量

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual int Count()
        => (int)this.Select.Count();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual long CountLong()
        => this.Select.Count();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual int Count(Expression<Func<T, bool>> expWhere)
        => (int)this.Select.Where(expWhere).Count();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual long CountLong(Expression<Func<T, bool>> expWhere)
        => this.Select.Where(expWhere).Count();

    /// <summary>
    /// 是否存在 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual bool Any(Expression<Func<T, bool>> expWhere)
        => this.Select.Any(expWhere);

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual async Task<int> CountAsync()
        => (int)await this.Select.CountAsync();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual Task<long> CountLongAsync()
        => this.Select.CountAsync();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual async Task<int> CountAsync(Expression<Func<T, bool>> expWhere)
        => (int)await this.Select.Where(expWhere).CountAsync();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<long> CountLongAsync(Expression<Func<T, bool>> expWhere)
        => this.Select.Where(expWhere).CountAsync();

    /// <summary>
    /// 是否存在 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<bool> AnyAsync(Expression<Func<T, bool>> expWhere)
        => this.Select.AnyAsync(expWhere);

    #endregion

}
